﻿//     Copyright (c) Microsoft Corporation.  All rights reserved.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Linq;
using System.Xml.XPath;
using Microsoft.Gateway.Configuration;
using Microsoft.Gateway.RulesConfigurator;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.Web.Administration;

namespace RulesConfigurator.UnitTests
{
    [TestClass]
    [Ignore]                // TODO: Re-enable when we can work MWA in non-admin mode or we admin rights on the build machine
    [DeploymentItem("web.config", "RulesConfigurator")]
    [DeploymentItem("applicationHost.config", "RulesConfigurator")]
    public class RulesConfiguratorTests
    {
        string webConfigFile;
        string appHostConfigFile;

        [TestInitialize]
        public void PrepareTestFolder()
        {
            webConfigFile = Path.GetFullPath("RulesConfigurator\\web.config");
            appHostConfigFile = Path.GetFullPath("RulesConfigurator\\applicationHost.config");
            using (var serverManager = new ServerManager(appHostConfigFile))
            {
                serverManager.Sites["Default Web Site"].Applications[0].VirtualDirectories[0].PhysicalPath = Path.GetDirectoryName(webConfigFile);
                serverManager.CommitChanges();
            }
        }
    
        [TestMethod]
        public void RulesConfiguratorNoCache()
        {
            var config = new RulesConfiguration
            {
                Directory = "gateway.onmicrosoft.com",
                ApplicationName = "fake name",
                Roles = new Dictionary<string, Role>(StringComparer.OrdinalIgnoreCase)
                {
                     { Role.ROLE_NAME_DEFAULT, new Role
                            {
                                Segment = Role.ROLE_NAME_DEFAULT,
                                Target = new List<TargetRoute>
                                {
                                    new TargetRoute { Redirect = "foo.com" },
                                },
                            }}
                },
            };
            var configState = Program.ApplyConfigurationUpdates(null, config, webConfigFile);
            Assert.IsTrue(configState.UpdateCache, "ConfiguratorState.UpdateCache should be true");
            Assert.IsFalse(configState.RetryLater, "ConfiguratorState.RetryLater should be false");
            Assert.IsTrue(configState.FailedExitCode == 0, "ConfiguratorState.FailedExitCode should be 0");

            XDocument webConfig = XDocument.Load(webConfigFile);
            var defaultRule = webConfig.XPathSelectElement("//configuration/system.webServer/rewrite/rules/rule[@name='Gateway__default_Default']");
            Assert.IsNotNull(defaultRule, "Default Rule should be present");
            var match = defaultRule.Element(XNamespace.None + "match");
            Assert.IsNotNull(match, "Match element should be present");
            Assert.AreEqual(match.Attribute(XNamespace.None + "url").Value, "(.*)");

            var targetUri = defaultRule.XPathSelectElement("serverVariables/set[@name='TARGET_URI']");
            Assert.IsNotNull(targetUri);
            Assert.AreEqual(targetUri.Attribute(XNamespace.None + "value").Value,
                "{C:1}foo.com/{R:1}",
                "TARGET_URI variable is not correct.");

            var wifIssuerRegistry = webConfig.XPathSelectElement("//configuration/system.identityModel/identityConfiguration/issuerNameRegistry");
            Assert.IsNotNull(wifIssuerRegistry, "WIF IssuerNameRegistry element is not present");
            Assert.AreEqual(wifIssuerRegistry.Element(XNamespace.None + "authority").Attribute(XNamespace.None + "name").Value,
                "https://sts.windows.net/0be2ee01-5b59-41c0-896e-cc87c828d0c7/",
                "IssuerNameRegistry authority is not for gateway.onmicrosoft.com");
        }

        [TestMethod]
        public void RulesConfiguratorAddAuthRemoveAuth()
        {
            var configWithAuth = new RulesConfiguration
            {
                Directory = "gateway.onmicrosoft.com",
                ApplicationName = "fake name",
                Roles = new Dictionary<string, Role>(StringComparer.OrdinalIgnoreCase)
                {
                     { Role.ROLE_NAME_DEFAULT, new Role
                            {
                                Segment = Role.ROLE_NAME_DEFAULT,
                                Target = new List<TargetRoute>
                                {
                                    new TargetRoute { Redirect = "foo.com" },
                                },
                            }}
                },
            };
            Program.ApplyConfigurationUpdates(null, configWithAuth, webConfigFile);

            XDocument webConfig = XDocument.Load(webConfigFile);
            var authZ = webConfig.XPathSelectElement("//configuration/system.web/authorization");
            Assert.IsTrue(authZ.Descendants().Count() == 1, "Should only be 1 <deny> authz element");
            Assert.IsTrue(authZ.Descendants(XNamespace.None + "deny").Count() == 1, "Should only be 1 <deny> authz element");
            Assert.AreEqual(authZ.Descendants().First().Attribute(XNamespace.None + "users").Value, 
                "?", "Unauthenticated users should be denied");

            var configNoAuth = new RulesConfiguration
            {
                Roles = new Dictionary<string, Role>(StringComparer.OrdinalIgnoreCase)
                {
                     { Role.ROLE_NAME_DEFAULT, new Role
                            {
                                Segment = Role.ROLE_NAME_DEFAULT,
                                Target = new List<TargetRoute>
                                {
                                    new TargetRoute { Redirect = "foo.com" },
                                },
                            }}
                },
            };
            Program.ApplyConfigurationUpdates(configWithAuth, configNoAuth, webConfigFile);
            webConfig = XDocument.Load(webConfigFile);
            authZ = webConfig.XPathSelectElement("//configuration/system.web/authorization");
            Assert.IsTrue(authZ.Descendants().Count() == 1, "Should only be 1 <allow> authz element");
            Assert.IsTrue(authZ.Descendants(XNamespace.None + "allow").Count() == 1, "Should only be 1 <allow> authz element");
            Assert.AreEqual(authZ.Descendants().First().Attribute(XNamespace.None + "users").Value,
                "*", "All users should be allowed");
            
        }
    }
}
